<?php
/**
 * Created by PhpStorm.
 * User: Rain
 * Date: 2020/5/21
 * Time: 21:59
 */

namespace app\service\alone\Path;


use app\service\alone\BaseService;
use app\service\alone\Encryption\EncryptionService;
use app\service\alone\File\FileService;
use app\service\interfaces\EncryptionInterface;
use app\service\interfaces\FileHandlerInterface;
use think\facade\Filesystem;

/**
 * Class PathService
 *
 * @property FileService $file
 * @property EncryptionService $encryption
 *
 * @package app\service\alone\Path
 */
class PathService extends BaseService
{
    protected $rely = [
        'file' => FileService::class,
        'encryption' => EncryptionService::class
    ];

    protected $isPath;

    protected function init()
    {
        // 是否加密
        $this->isPath = config('app.path') ? true : false;
    }

    /**
     * 替换服务类
     *
     * @param FileHandlerInterface $fileHandler
     * @param EncryptionInterface $encryption
     * @return $this
     */
    public function make(FileHandlerInterface $fileHandler, EncryptionInterface $encryption)
    {
        $this->rely = [
            'file' => get_class($fileHandler),
            'encryption' => get_class($encryption)
        ];

        return $this;
    }

    /**
     * 生成加密url
     *
     * @param string $path
     * @return array
     * @throws \Exception
     */
    public function generateUrl(string $path): array
    {
        $result = $this->file->exists($path);
        if (200 != $result['code']) return [
            'url' => '',
            'input' => '',
        ];

        if ($this->isPath) {
            $input = $this->encryption->encryption($path);

            $url = url('admin-file', ['input' => $input]);
        } else {
            $storage = Filesystem::disk('public')->getConfig()->get('url');

            // 生成访问地址
            $url = $storage . '/' . $path;
            $input = $path;
        }

        return [
            'url' => request()->domain() . $url,
            'input' => $input,
        ];
    }

    /**
     * 验证并复制图片
     *
     * @param string $input
     * @return bool
     */
    public function fileHandler(string $input)
    {
        if ($this->isPath) {
            if (!$path = $this->encryption->decrypt($input)) return false;
        } else {
            $path = $input;
        }

        $result = $this->file->cp($path);
        if (200 != $result['code']) return false;

        return $result['data']['path'];
    }

    /**
     * 处理富文本中的图片（展示）
     *
     * @param string $description
     * @param bool $domain 是否使用全域名
     * @return string
     * @throws \Exception
     */
    public function richTextEncryptionPath(string $description, bool $domain = false): string
    {
        $description = preg_replace_callback('/<[source|img][\s\S]*?src\s*=\s*[\"|\'](.*?)[\"|\'][\s\S]*?>/', function ($matches) use ($domain) {
            // 网络链接不做处理
            $prefix = substr($matches[1], 0, 10);
            if (strstr($prefix, 'http') || strstr($prefix, 'https')) return $matches[0];

            // 是否使用全域名
            if (!$domain) return $matches[0];

            // 文件路径加密
            $path = $this->generateUrl($matches[1]);

            // 替换 src 链接
            return str_replace($matches[1], $path['url'], $matches[0]);
        }, $description);

        return $description;
    }

    /**
     * 处理富文本中的图片（存储）
     *
     * @param string $description
     * @return array
     */
    public function richTextPath(string $description): array
    {
        // 正则匹配最大回溯数 1千万
        ini_set('pcre.backtrack_limit', 10000000);

        try {
            $description = preg_replace_callback('/<[source|img][\s\S]*?src\s*=\s*[\"|\'](.*?)[\"|\'][\s\S]*?>/', function ($matches) {
                // 网络链接不做处理
                $prefix = substr($matches[1], 0, 10);
                if ((strstr($prefix, 'http') || strstr($prefix, 'https'))) return $matches[0];

                // 处理文件，是否需存储
                if (false === $path = $this->fileHandler($matches[1])) throw new \Exception('', 303);

                // 替换 src 链接
                return str_replace($matches[1], $path, $matches[0]);
            }, $description);
        } catch (\Exception $exception) {
            return echoArr($exception->getCode() ?: 500, $exception->getMessage());
        }

        return echoArr(200, '请求成功', $description);
    }
}
